package top.xzhanyao.scaffold.common.tree.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import top.xzhanyao.scaffold.common.tree.model.AbstractRoot;
import top.xzhanyao.scaffold.common.tree.model.Leaf;

import java.lang.reflect.Field;
import java.util.List;

/**
 * 树工具类
 * @author Zhan Yao
 *
 * 2017年11月7日
 */
@Slf4j
public class TreeUtil {

    /**
     * 根据 idName 和 parentIdName 生成树
     * @param list 需要生成树的数据
     * @param idName id的属性名
     * @param pIdName pId的属性名
     * @param rootPIdValue 一级pId的值
     * @return 树结构的数据
     */
    public static <T> AbstractRoot<T> getTree(List<T> list, String idName, String pIdName, Object rootPIdValue) {
        AbstractRoot<T> root = new Leaf<>();
        for (T t : list) {
            Class<?> clasz = t.getClass();
            try {
                Field pIdfield = clasz.getDeclaredField(pIdName);
                // 设置允许获取私有成员变量
                pIdfield.setAccessible(true);
                Object pId = pIdfield.get(t);
                if (pId == null || pId.equals(rootPIdValue)) {
                    addLeaf(list, idName, pIdName, root, t, clasz);
                }
            } catch (Exception e) {
                log.error(ExceptionUtils.getStackTrace(e));
            }
        }
        return root;
    }

    private static <T> void getChild(List<T> list, String idName, String pIdName, Leaf<T> branch, Object pId)
            throws Exception {
        for (T t : list) {
            Class<?> clasz = t.getClass();
            Field pIdfield = clasz.getDeclaredField(pIdName);
            // 设置允许获取私有成员变量
            pIdfield.setAccessible(true);
            Object tPId = pIdfield.get(t);
            if (pId.equals(tPId)) {
                addLeaf(list, idName, pIdName, branch, t, clasz);
            }
        }
    }

    private static <T> void addLeaf(List<T> list, String idName, String pIdName, AbstractRoot<T> root, T t, Class<?> clasz)
            throws Exception {
        Leaf<T> leaf = new Leaf<>();
        Field idfield = clasz.getDeclaredField(idName);
        // 设置允许获取私有成员变量
        idfield.setAccessible(true);
        Object id = idfield.get(t);
        leaf.setT(t);
        getChild(list, idName, pIdName, leaf, id);
        root.add(leaf);
    }
    
}
